package com.och.mrcp.core.rtp.session;

import com.och.mrcp.core.rtp.model.RtpPacket;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * RTP抖动缓冲区
 * 处理网络延迟和包乱序问题
 */
@Slf4j
public class JitterBuffer {
    
    // 缓冲区大小配置
    private static final int DEFAULT_BUFFER_SIZE = 10;
    private static final int MAX_BUFFER_SIZE = 50;
    private static final long DEFAULT_TIMEOUT_MS = 1000; // 1秒超时
    
    // 缓冲区 - 优化并发性能
    private final ConcurrentHashMap<Integer, RtpPacket> packetBuffer = new ConcurrentHashMap<>(64);
    private final ConcurrentLinkedQueue<Integer> sequenceQueue = new ConcurrentLinkedQueue<>();
    
    // 统计信息
    private final AtomicInteger totalPackets = new AtomicInteger(0);
    private final AtomicInteger droppedPackets = new AtomicInteger(0);
    private final AtomicInteger outOfOrderPackets = new AtomicInteger(0);
    
    // 读写锁优化并发访问
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
    
    // 配置参数
    private int bufferSize = DEFAULT_BUFFER_SIZE;
    private long timeoutMs = DEFAULT_TIMEOUT_MS;
    private int expectedSequenceNumber = 0;
    
    public JitterBuffer() {
        this(DEFAULT_BUFFER_SIZE, DEFAULT_TIMEOUT_MS);
    }
    
    public JitterBuffer(int bufferSize, long timeoutMs) {
        this.bufferSize = Math.min(bufferSize, MAX_BUFFER_SIZE);
        this.timeoutMs = timeoutMs;
        log.debug("JitterBuffer initialized with size={}, timeout={}ms", bufferSize, timeoutMs);
    }
    
    /**
     * 添加RTP包到缓冲区
     */
    public void addPacket(RtpPacket packet) {
        if (packet == null) {
            return;
        }
        
        int seqNum = packet.getSequenceNumber();
        totalPackets.incrementAndGet();
        
        // 检查是否是第一个包
        if (packetBuffer.isEmpty()) {
            expectedSequenceNumber = seqNum;
        }
        
        // 检查序列号是否在预期范围内
        int seqDiff = getSequenceDifference(expectedSequenceNumber, seqNum);
        
        if (seqDiff < 0) {
            // 包太旧，丢弃
            log.debug("Dropping old packet: expected={}, received={}", expectedSequenceNumber, seqNum);
            droppedPackets.incrementAndGet();
            return;
        }
        
        if (seqDiff > bufferSize) {
            // 包太新，缓冲区已满
            log.debug("Buffer full, dropping packet: seq={}", seqNum);
            droppedPackets.incrementAndGet();
            return;
        }
        
        // 添加到缓冲区
        packetBuffer.put(seqNum, packet);
        sequenceQueue.offer(seqNum);
        
        // 检查是否有乱序包
        if (seqDiff > 1) {
            outOfOrderPackets.incrementAndGet();
            log.debug("Out of order packet: expected={}, received={}", expectedSequenceNumber, seqNum);
        }
        
        // 清理过期包
        cleanupExpiredPackets();
        
        log.debug("Packet added to buffer: seq={}, bufferSize={}", seqNum, packetBuffer.size());
    }
    
    /**
     * 获取下一个可用的RTP包
     */
    public RtpPacket getNextPacket() {
        readLock.lock();
        try {
        // 查找下一个预期的包
        RtpPacket packet = packetBuffer.get(expectedSequenceNumber);
        if (packet != null) {
            // 移除已处理的包
            packetBuffer.remove(expectedSequenceNumber);
            sequenceQueue.remove(expectedSequenceNumber);
            
            // 更新预期序列号
            expectedSequenceNumber = (expectedSequenceNumber + 1) & 0xFFFF;
            
            log.debug("Packet retrieved: seq={}, remaining={}", 
                    packet.getSequenceNumber(), packetBuffer.size());
            
            return packet;
        }
        
        // 如果没有找到预期的包，尝试查找下一个可用的包
        Integer nextSeq = findNextAvailableSequence();
        if (nextSeq != null) {
            packet = packetBuffer.get(nextSeq);
            if (packet != null) {
                packetBuffer.remove(nextSeq);
                sequenceQueue.remove(nextSeq);
                
                // 更新预期序列号
                expectedSequenceNumber = (nextSeq + 1) & 0xFFFF;
                
                log.debug("Packet retrieved (out of order): seq={}, remaining={}", 
                        nextSeq, packetBuffer.size());
                
                return packet;
            }
        }
        
        return null;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 查找下一个可用的序列号
     */
    private Integer findNextAvailableSequence() {
        for (Integer seq : sequenceQueue) {
            if (packetBuffer.containsKey(seq)) {
                return seq;
            }
        }
        return null;
    }
    
    /**
     * 计算序列号差值
     */
    private int getSequenceDifference(int expected, int actual) {
        int diff = actual - expected;
        if (diff > 32767) {
            diff -= 65536; // 处理序列号回绕
        } else if (diff < -32768) {
            diff += 65536;
        }
        return diff;
    }
    
    /**
     * 清理过期的包
     */
    private void cleanupExpiredPackets() {
        long currentTime = System.currentTimeMillis();
        
        packetBuffer.entrySet().removeIf(entry -> {
            RtpPacket packet = entry.getValue();
            long arrival = packet.getArrivalTimeMs();
            long packetAge = (arrival > 0 ? currentTime - arrival : 0);
            if (arrival > 0 && packetAge > timeoutMs) {
                log.debug("Removing expired packet: seq={}, age={}ms", 
                        packet.getSequenceNumber(), packetAge);
                droppedPackets.incrementAndGet();
                return true;
            }
            return false;
        });
        
        // 清理序列号队列中的无效引用
        sequenceQueue.removeIf(seq -> !packetBuffer.containsKey(seq));
    }
    
    /**
     * 获取缓冲区状态
     */
    public JitterBufferStats getStats() {
        JitterBufferStats stats = new JitterBufferStats();
        stats.setBufferSize(bufferSize);
        stats.setCurrentSize(packetBuffer.size());
        stats.setTotalPackets(totalPackets.get());
        stats.setDroppedPackets(droppedPackets.get());
        stats.setOutOfOrderPackets(outOfOrderPackets.get());
        stats.setExpectedSequenceNumber(expectedSequenceNumber);
        stats.setTimeoutMs(timeoutMs);
        
        return stats;
    }
    
    /**
     * 清空缓冲区
     */
    public void clear() {
        packetBuffer.clear();
        sequenceQueue.clear();
        expectedSequenceNumber = 0;
        log.debug("JitterBuffer cleared");
    }
    
    /**
     * 设置缓冲区大小
     */
    public void setBufferSize(int newSize) {
        this.bufferSize = Math.min(newSize, MAX_BUFFER_SIZE);
        log.debug("JitterBuffer size changed to: {}", this.bufferSize);
    }
    
    /**
     * 设置超时时间
     */
    public void setTimeoutMs(long newTimeout) {
        this.timeoutMs = newTimeout;
        log.debug("JitterBuffer timeout changed to: {}ms", this.timeoutMs);
    }
    
    /**
     * 检查缓冲区是否为空
     */
    public boolean isEmpty() {
        return packetBuffer.isEmpty();
    }
    
    /**
     * 获取缓冲区当前大小
     */
    public int size() {
        return packetBuffer.size();
    }
}
